package com.example.demo.T2.service;


import com.example.demo.T2.pojo.Car;
import com.example.demo.T2.util.FakeTimer;
import com.example.demo.T2.util.TollCheckTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 收费站
 */
public class TollWorker implements Runnable {

    static Logger LOGGER = LoggerFactory.getLogger(TollWorker.class.getName());

    private String name;

    /**进入收费站*/
    private Queue<Car> globalWaitingQueue;
    /**离开收费站*/
    private Queue<Car> globalDeliverQueue;

    private ReentrantReadWriteLock globalLock;

    /**当前线程排队数量*/
    private Queue<Car> waitingQueue;

    /**当前随机等待时键*/
    private long current;

    /**当前窗口总共排队时长*/
    volatile long totalWaitingTime;


    /**本地锁，用来唤醒 */
    private Lock workLock = new ReentrantLock(true);

    private Condition condition = workLock.newCondition();


    /**当前收费窗口等待策略*/
    private Map<String, TollCheckTime> waitStrategyMap;

    private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm:ss");

    private FakeTimer fakeTimer;

    public TollWorker(String name, FakeTimer fakeTimer, Queue<Car> waiting, Map<String, TollCheckTime> waitStrategyMap, ReentrantReadWriteLock globalLock, Queue<Car> globalWaitingQueue, Queue<Car> globalDeliverQueue) {
        this.name = name;
        this.waitingQueue = waiting;
        this.waitStrategyMap = waitStrategyMap;
        this.globalLock = globalLock;
        this.globalWaitingQueue = globalWaitingQueue;
        this.globalDeliverQueue = globalDeliverQueue;
        this.fakeTimer = fakeTimer;
        ;

    }

    /**
     * 当前服务窗口添加线程
     * @param car
     */
    void add(Car car) {
        // 用于唤醒使用
        globalLock.writeLock().lock();
        workLock.lock();
        try {
            car.setArriveAt(fakeTimer.getCurrentFakeMiutes());
            this.waitingQueue.add(car);
            plusTotalWaitTime(car);
            globalWaitingQueue.add(car);
            // 唤醒在睡觉的线程
            condition.signal();
        } finally {
            workLock.unlock();
            globalLock.writeLock().unlock();
        }
    }

    /**
     * 离开收费站
     * @param car
     */
    void leave(Car car) {
        // 保证此刻没有线程排序
        globalLock.writeLock().lock();
        try {
            car.setDuration(car.getArriveAt()+ " ~ " +(car.getArriveAt()+current));
            waitingQueue.poll();
            globalDeliverQueue.add(car);
            minusTotalWaitTime(car);
        } finally {
            globalLock.writeLock().unlock();
        }

    }

    void clear() {
        workLock.lock();
        try {
            waitingQueue.clear();
            this.totalWaitingTime = 0;
        } finally {
            workLock.unlock();
        }
    }

    /**
     * 计算当前队列的平均时长
     * @param car
     * @return
     */
    private void plusTotalWaitTime(Car car) {
        TollCheckTime waitTimer = waitStrategyMap.get(car.getCarType());
        if (waitTimer == null) return;
        this.totalWaitingTime += waitTimer.getAverageTime();
    }

    /**
     * 减去排队时间
     * @param car
     */
    private void minusTotalWaitTime(Car car) {
        TollCheckTime waitTimer = waitStrategyMap.get(car.getCarType());
        if (waitTimer == null) return;
        this.totalWaitingTime -= waitTimer.getAverageTime();
    }


    @Override
    public void run() {
        while (true) {
            try {
                // 进入收费站，开始办手续
                Car car = this.waitingQueue.peek();
                if (car == null) {
                    this.workLock.lock();
                    try {
                        condition.await();
                        continue;
                    } finally {
                        this.workLock.unlock();
                    }
                }
                // 获取等待策略
                TollCheckTime waitTimer = waitStrategyMap.get(car.getCarType());
                if (waitTimer == null) {
                    throw new RuntimeException("获取WaitTimer时间失败！");
                }
                // 随机等待时间,睡眠
                current = waitTimer.getWaitingTime(); //
                long v = (long) fakeTimer.fake2Real(current * 60);

                TimeUnit.SECONDS.sleep(v);
                // 过收费站
                leave(car);

            } catch (InterruptedException e) {
                LOGGER.warn("线程中断:" + e.getMessage());
            }
            current = 0;
        }

    }


    public String getName() {
        return name;
    }

    public Queue<Car> getWaitingQueue() {
        return waitingQueue;
    }


    public long getTotalWaitingTime() {
        return totalWaitingTime;
    }
}
